Задан набор
чисел a1, ..., an. Для заданных индексов l и r
найдите
Вход. В первой строке записано количество чисел n (1 ≤ n ≤ 106). Во второй строке записаны числа ai (1 ≤ ai ≤ 1000), разделенные
пробелом. В третьей строке записано количество запросов m (1 ≤ m ≤ 106).
Далее на отдельных строках записаны сами запросы li и ri
(1 ≤ li ≤ ri ≤ n).
Выход. Выведите в
отдельных строках m чисел Sli..ri.
Пример
входа |
Пример
выхода |
5 1 2 3 4 5 5 1 5 2 3 3 4 2 5 1 4 |
15 5 7 14 10 |
частичные
суммы
Каждый запрос Sl,r можно выполнять
при помощи цикла за время O(n).
Имеется m ≤ 106 запросов,
длина массива составляет n ≤ 106.
При линейном времени выполнения запроса нам потребуется не более n * m ≤ 1012
операций, что даст Time Limit.
Рссмотрим
частичные суммы массива а:
s1 = a1;
s2 = a1 + a2;
s3 = a1 + a2 + a3;
. . .
sn = a1
+ a2 + a3 + . . . + an;
Вычислить
значения s1, s2, …, sn можно в линейном массиве s за время O(n).
Далее заметим,
что
Sl,r = al + al + 1 + … + ar =
= (a1
+ … + al + al + 1 + … + ar) – (a1 + … + al-1) = sr – sl-1
Таким образом
ответить на запрос Sl,r можно за O(1), то есть за константное время.
Пример
Вычислим сумму a3 + a4 + a5 для приведенного в условии примера.
Имеем: a3 + a4 + a5 = s5 – s2 = 15 – 3 = 12.
Реализация алгоритма
Объявим два рабочих двумерных массива.
#define MAX 1000001
int a[MAX], s[MAX];
Читаем входной набор чисел в массив a, вычисляем частичные суммы в массиве s.
scanf("%d",&n);
s[0] = 0;
for(i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
s[i] = s[i-1] + a[i];
}
Обрабатываем m
запросов.
scanf("%d",&m);
for(i = 0; i < m; i++)
{
scanf("%d
%d",&b,&c);
printf("%d\n",s[c]
- s[b-1]);
}
Реализация алгоритма – SQRT декомпозиция - TLE
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
int i, n, m, len, x, y;
vector<int> a, b;
int q(int l, int r)
{
int i, sum = 0;
int c_l = l / len, c_r = r / len;
if (c_l == c_r)
for (i =
l; i <= r; i++)
sum += a[i];
else
{
for (i =
l; i <= (c_l + 1)*len -
1; i++)
sum
+= a[i];
for (i =
c_l + 1; i <= c_r - 1;
i++)
sum += b[i];
for (i =
c_r * len; i <= r; i++)
sum += a[i];
}
return sum;
}
int main(void)
{
scanf("%d",
&n);
a.resize(n);
for (i =
0; i < n; i++)
scanf("%d",
&a[i]);
len
= sqrt(n) + 1;
b.resize(len);
for (i = 0; i <
n; i++)
b[i / len] += a[i];
scanf("%d",
&m);
for (i = 0; i <
m; i++)
{
scanf("%d
%d", &x, &y);
printf("%d\n", q(x
- 1, y - 1));
}
return 0;
}
Реализация алгоритма – запрос за линейное время - TLE
#include <stdio.h>
#define MAX 1000001
int i, j, n, m, b, c, s;
int a[MAX];
int main(void)
{
scanf("%d",
&n);
for (i = 1; i <=
n; i++)
scanf("%d",
&a[i]);
scanf("%d",
&m);
for (i = 0; i <
m; i++)
{
scanf("%d
%d", &b, &c);
s = 0;
for (j =
b; j <= c; j++)
s = s + a[j];
printf("%d\n", s);
}
return 0;
}
Python реализация
Читаем входные
данные.
n = int(input())
a = [0] + list(map(int, input().split()))
В списке s
вычисляем частичные суммы списка а.
s = [0] * (n + 1)
for i in range(1, n + 1):
s[i] = s[i - 1] + a[i]
Обрабатываем m запросов.
m = int(input())
for _ in range(m):
b, c = map(int, input().split())
print(s[c] - s[b - 1])